package com.atguigu.daijia.dispatch.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.daijia.common.constant.RedisConstant;
import com.atguigu.daijia.common.execption.GuiguException;
import com.atguigu.daijia.common.result.Result;
import com.atguigu.daijia.common.result.ResultCodeEnum;
import com.atguigu.daijia.dispatch.mapper.OrderJobMapper;
import com.atguigu.daijia.dispatch.service.NewOrderService;
import com.atguigu.daijia.dispatch.xxl.client.XxlJobClient;
import com.atguigu.daijia.map.client.MapFeignClient;
import com.atguigu.daijia.model.entity.dispatch.OrderJob;
import com.atguigu.daijia.model.enums.OrderStatus;
import com.atguigu.daijia.model.form.map.SearchNearByDriverForm;
import com.atguigu.daijia.model.form.order.OrderInfoForm;
import com.atguigu.daijia.model.vo.dispatch.NewOrderTaskVo;
import com.atguigu.daijia.model.vo.map.NearByDriverVo;
import com.atguigu.daijia.model.vo.order.NewOrderDataVo;
import com.atguigu.daijia.order.client.OrderInfoFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class NewOrderServiceImpl implements NewOrderService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private OrderInfoFeignClient orderInfoFeignClient;
    @Autowired
    private MapFeignClient mapFeignClient;

    @Autowired
    private XxlJobClient xxlJobClient;

    @Autowired
    private OrderJobMapper orderJobMapper;
    /**
     * 添加任务并开启任务
     *
     * @param newOrderTaskVo
     * @return JobId
     */
    @Override
    public Long addAndStartTask(NewOrderTaskVo newOrderTaskVo) {
        //先查询数据库中是否有当前任务
        LambdaQueryWrapper<OrderJob> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderJob::getOrderId,newOrderTaskVo.getOrderId());
        OrderJob orderJob = orderJobMapper.selectOne(queryWrapper);
        if (!Optional.ofNullable(orderJob).isPresent()) {
            orderJob = new OrderJob();
            //添加任务
            Long jobId = xxlJobClient.addAndStart("newOrderTask", "",
                    "0 0/1 * * * ?", "添加订单任务" + newOrderTaskVo.getOrderId());
            orderJob.setJobId(jobId);
            orderJob.setOrderId(newOrderTaskVo.getOrderId());
            orderJob.setParameter(JSONObject.toJSONString(newOrderTaskVo));
            orderJobMapper.insert(orderJob);
        }
        return orderJob.getJobId();
    }

    /**
     * 执行新建订单相关任务内容
     *
     * @param jobId
     */
    @Override
    public void excuteTask(long jobId) {
        //1.先查询数据库中是否有当前订单任务
        LambdaQueryWrapper<OrderJob> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderJob::getJobId,jobId);
        OrderJob orderJob = orderJobMapper.selectOne(queryWrapper);
        if (!Optional.ofNullable(orderJob).isPresent()) {
            return;
        }
        //根据订单id查询当前订单状态 未接单：执行任务 已接单：结束任务
        String parameter = orderJob.getParameter();
        NewOrderTaskVo newOrderTaskVo = JSONObject.parseObject(parameter, NewOrderTaskVo.class);
        Long orderId = newOrderTaskVo.getOrderId();
        Result<Integer> orderStatus = orderInfoFeignClient.getOrderStatus(orderId);
        if (orderStatus.getCode() !=200) {
            throw new GuiguException(ResultCodeEnum.FEIGN_FAIL);
        }
        if (!Objects.equals(orderStatus.getData(), OrderStatus.WAITING_ACCEPT.getStatus())) {
            return;
        }

        //远程调用地图服务查询可以接单的司机
        SearchNearByDriverForm searchNearByDriverForm = new SearchNearByDriverForm();
        searchNearByDriverForm.setLatitude(newOrderTaskVo.getStartPointLatitude());
        searchNearByDriverForm.setLongitude(newOrderTaskVo.getStartPointLongitude());
        searchNearByDriverForm.setMileageDistance(newOrderTaskVo.getExpectDistance());

        Result<List<NearByDriverVo>> driverResult = mapFeignClient.searchNearByDriver(searchNearByDriverForm);

        // 遍历司机集合，得到每个司机，为每个司机创建临时队列，存储新订单信息
        List<NearByDriverVo> driverList = driverResult.getData();
        for (NearByDriverVo nearByDriverVo : driverList) {
            //使用Redis中的set类型存入当前订单下已经接收到信息的司机集合
            String repeatKey = RedisConstant.DRIVER_ORDER_REPEAT_LIST+orderId.toString();
            //判断当前司机是否已经接单
            Boolean isMember = stringRedisTemplate.opsForSet().isMember(repeatKey, nearByDriverVo.getDriverId());
            if (BooleanUtils.isTrue(isMember)) {
                continue; //跳过
            }
            //将当前司机添加到已经提醒接单司机中 并设置过期时间：15分钟，超过15分钟没有接单自动取消
            stringRedisTemplate.opsForSet().add(repeatKey,nearByDriverVo.getDriverId().toString());
            stringRedisTemplate.expire(repeatKey,RedisConstant.DRIVER_ORDER_REPEAT_LIST_EXPIRES_TIME, TimeUnit.MINUTES);

            //将订单信息添加到当前司机临时队列中
            String tempKey = RedisConstant.DRIVER_ORDER_TEMP_LIST+nearByDriverVo.getDriverId().toString();
            NewOrderDataVo newOrderDataVo = new NewOrderDataVo();
            newOrderDataVo.setOrderId(newOrderTaskVo.getOrderId());
            newOrderDataVo.setStartLocation(newOrderTaskVo.getStartLocation());
            newOrderDataVo.setEndLocation(newOrderTaskVo.getEndLocation());
            newOrderDataVo.setExpectAmount(newOrderTaskVo.getExpectAmount());
            newOrderDataVo.setExpectDistance(newOrderTaskVo.getExpectDistance());
            newOrderDataVo.setExpectTime(newOrderTaskVo.getExpectTime());
            newOrderDataVo.setFavourFee(newOrderTaskVo.getFavourFee());
            newOrderDataVo.setDistance(nearByDriverVo.getDistance());
            newOrderDataVo.setCreateTime(newOrderTaskVo.getCreateTime());

            stringRedisTemplate.opsForList().leftPush(tempKey,JSONObject.toJSONString(newOrderDataVo));
            stringRedisTemplate.expire(tempKey,RedisConstant.DRIVER_ORDER_TEMP_LIST_EXPIRES_TIME,TimeUnit.MINUTES);

        }
    }

    /**
     * 查询司机能够接的新订单
     *
     * @param driverId
     * @return
     */
    @Override
    public List<NewOrderDataVo> findNewOrderQueueData(Long driverId) {
        List<NewOrderDataVo> list = new ArrayList<>();
        String key = RedisConstant.DRIVER_ORDER_TEMP_LIST + driverId;
        Long size = stringRedisTemplate.opsForList().size(key);
        if(size > 0) {
            for (int i = 0; i < size; i++) {
                String content = stringRedisTemplate.opsForList().leftPop(key);
                NewOrderDataVo newOrderDataVo = JSONObject.parseObject(content,NewOrderDataVo.class);
                list.add(newOrderDataVo);
            }
        }
        return list;
    }

    /**
     * 清空新订单
     *
     * @param driverId
     * @return
     */
    @Override
    public Boolean clearNewOrderQueueData(Long driverId) {
        //清空Redis中缓存的订单信息
        String key = RedisConstant.DRIVER_ORDER_TEMP_LIST+driverId;
        stringRedisTemplate.delete(key);
        return true;
    }
}
